﻿using System;
using System.Linq;
using System.Web;
using System.Web.Mvc;

using SimpleForum.Utils;
using SimpleForum.Data.Models;
using SimpleForum.Data.Services;
using SimpleForum.Data.Repositories;
using SimpleForum.Classes.Core.Providers;
using SimpleForum.Data.Models.ViewModels;

using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;

namespace SimpleForum.Controllers
{
    public class UserController : BaseController
    {
        private readonly IRepository<User> UserRepository;
        private readonly IUserService UserService;
        private UserProvider UserProvider;

        public UserController(IRepository<User> UserRepository, IUserService UserService)
        {
            this.UserRepository = UserRepository;
            this.UserService = UserService;
        }

        protected override void Initialize(System.Web.Routing.RequestContext requestContext)
        {
            if (UserProvider == null) this.UserProvider = new UserProvider(this.UserRepository);

            base.Initialize(requestContext);
        }

        public ActionResult View(int id, string name, string param)
        {
            var User = UserService.GetUser(id);

            if (User != null)
            {
                var ViewModel = new UserViewModel
                {
                    User = User,
                    IsSelf = (Identity != null ? (User.Id == Identity.User.Id) : false)
                };

                switch (param)
                {
                    case "profile": default: ViewModel.CurrentView = "Profile"; break;
                    case "statistics":
                        ViewModel.CurrentView = "Statistics";
                        var ConsideredRating = (from p in User.PostRatings
                                group p by p.RatingName into g
                                select new PostRating { RatingName = g.Key }).FirstOrDefault();
                        ViewModel.ConsideredRating = (ConsideredRating != null ? ConsideredRating.RatingName : null);

                        break;
                }

                if (HttpContext.Request.IsAjaxRequest()) return PartialView("ViewParts/" + ViewModel.CurrentView, ViewModel);
                else return View(ViewModel);
            }
            else return EntityNotFound();
        }

        public ActionResult Login()
        {
            return View();
        }

        [HttpPost, ValidateAntiForgeryToken]
        public ActionResult Login(FormCollection Credentials)
        {
            if (Credentials["Email"] != null && Credentials["Password"] != null)
            {
                if (UserService.Login(Credentials["Email"], Credentials["Password"]))
                {
                    if (Request.QueryString["ReturnUrl"] != null) return Redirect(Request.QueryString["ReturnUrl"]);
                    else return RedirectToAction("Index", "Category");
                }
                else
                {
                    ModelState.AddModelError("error", "Invalid username and password.");

                    return View();
                }
            }
            else
            {
                return Notification(NotificationHelper.NotificationTypes.Error, "No credentials");
            }
        }

        public ActionResult LoginOpenID(FormCollection Credentials)
        {
            DotNetOpenAuth.OpenId.RelyingParty.OpenIdRelyingParty OpenID = new DotNetOpenAuth.OpenId.RelyingParty.OpenIdRelyingParty();
            var OpenResponse = OpenID.GetResponse();

            if (OpenResponse == null)
            {
                Identifier ID;
                if (Identifier.TryParse(Credentials["openid_identifier"], out ID))
                {
                    try
                    {
                        var Request = OpenID.CreateRequest(Credentials["openid_identifier"]);
                        var FetchRequest = new FetchRequest();

                        FetchRequest.Attributes.Add(new AttributeRequest(WellKnownAttributes.Contact.Email, true));
                        FetchRequest.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.Alias, true));
                        Request.AddExtension(FetchRequest);

                        return Request.RedirectingResponse.AsActionResult();
                    }
                    catch (ProtocolException E)
                    {
                        ModelState.AddModelError("error", E.Message);

                        return View("Login");
                    }
                }
                else
                {
                    ModelState.AddModelError("error", "Invalid Identifier");

                    return View("Login");
                }
            }
            else
            {
                switch (OpenResponse.Status)
                {
                    case DotNetOpenAuth.OpenId.RelyingParty.AuthenticationStatus.Authenticated:
                        string Email = null, Alias = null, Identifier = OpenResponse.FriendlyIdentifierForDisplay;

                        var FetchResponse = OpenResponse.GetExtension<FetchResponse>();
                        if (FetchResponse != null)
                        {
                            if (FetchResponse.GetAttributeValue(WellKnownAttributes.Name.Alias) != null) Alias = FetchResponse.GetAttributeValue(WellKnownAttributes.Name.Alias);
                            if (FetchResponse.GetAttributeValue(WellKnownAttributes.Contact.Email) != null) Email = FetchResponse.GetAttributeValue(WellKnownAttributes.Contact.Email);
                        }

                        // if we've got an email address back from the OP then attempt to find if the user is already registered
                        if (Email != null)
                        {
                            var User = UserService.GetUserByEmail(Email);

                            if (User == null)
                            {
                                return View("Register", new UserRegisterViewModel
                                {
                                    Email = Email,
                                    UserName = (Alias ?? Email.Split('@')[0]) // if we can't pull an alias from the OP then try and offer a username from their e-mail address
                                });
                            }
                            else
                            {
                                UserService.CreateAuthTicket(((Email ?? Alias) ?? Identifier));

                                return RedirectToAction("Index", "Category");
                            }
                        }
                        
                        return RedirectToAction("Register");

                    default:
                        return Notification(NotificationHelper.NotificationTypes.Error, OpenResponse.Status.ToString());
                }
            }
        }

        public ActionResult Logout()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Logout(FormCollection Form)
        {
            UserService.Logout();

            return RedirectToAction("Index", "Category");
        }

        public ActionResult Register()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Register(UserRegisterViewModel NewUser)
        {
            if (ModelState.IsValid)
            {
                System.Web.Security.MembershipCreateStatus Status;

                if (NewUser.Password != NewUser.PasswordConfirm) Status = System.Web.Security.MembershipCreateStatus.InvalidPassword;
                else UserService.CreateUser(NewUser.UserName, NewUser.Email, NewUser.Password, null, out Status);

                if (Status == System.Web.Security.MembershipCreateStatus.Success)
                {
                    UserService.Login(NewUser.Email, NewUser.Password);

                    return RedirectToAction("Login", "User");
                }
                else
                {
                    ModelState.AddModelError("error", Status.ToString());

                    return View();
                }
            }
            else return View();
        }

        [Classes.Attributes.Ajax]
        public ActionResult CheckIfEmailExists(string Email)
        {
            return Json((UserService.GetUserByEmail(Email) == null), JsonRequestBehavior.AllowGet);
        }

        [Classes.Attributes.Ajax]
        public ActionResult CheckIfUsernameExists(string Email)
        {
            return Json((UserService.GetUserByUsername(Email) == null), JsonRequestBehavior.AllowGet);
        }

        [Classes.Attributes.Ajax, OutputCache(Duration = 86400, VaryByParam = "Username")]
        public ActionResult GetFacebookSocialCard(string Username)
        {
            try
            {
                string FacebookURI = String.Format("http://graph.facebook.com/{0}?fields=name,picture", Username);
                string JSON = new System.Net.WebClient().DownloadString(FacebookURI);
                var FacebookUser = new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<FacebookSocialCardViewModel>(JSON);

                if (FacebookUser.id != 0) return PartialView(FacebookUser);
                else throw new Exception("Facebook user not found");
            }
            catch
            {
                return new EmptyResult();
            }
        }

        [Classes.Attributes.Ajax, OutputCache(Duration = 86400, VaryByParam = "Username")]
        public ActionResult GetTwitterSocialCard(string Username)             
        {
            try
            {
                System.Xml.Linq.XDocument TwitterXML = System.Xml.Linq.XDocument.Load(String.Format("http://twitter.com/users/{0}.xml", Username));

                if (TwitterXML != null)
                {
                    return PartialView(new TwitterSocialCardViewModel
                    {
                        id = long.Parse(TwitterXML.Element("user").Element("id").Value),
                        name = TwitterXML.Element("user").Element("screen_name").Value,
                        picture = TwitterXML.Element("user").Element("profile_image_url").Value,
                        followers = Int32.Parse(TwitterXML.Element("user").Element("followers_count").Value)
                    });
                }
                else throw new Exception("Twitter user not found");
            }
            catch
            {
                return new EmptyResult();
            }
        }

        [Authorize, Classes.Attributes.Ajax, HttpPost]
        public void SaveBio(string Bio)
        {
            if (User.Identity.IsAuthenticated) UserService.UpdateField(Identity.User.Id, Data.Services.UserService.Fields.Bio, Bio);
        }

        [ChildActionOnly]
        public ActionResult Notifications()
        {
            if (User.Identity.IsAuthenticated)
            {
                var Notifications = UserService.GetNotifications(Identity.User.Id);

                if (Notifications != null) return PartialView(Notifications);
                else return null;
            }
            else return null;
        }

        [Classes.Attributes.Ajax, HttpPost]
        public void ReadNotification(int id)
        {
            if (User.Identity.IsAuthenticated) UserService.ReadNotification(Identity.User.Id, id);
        }
    }
}
